/* eslint-disable class-methods-use-this */

import { DbColumn } from '../../models/dbColumn'
import { DbForeignKey } from '../../models/dbForeignKey'
import { DbIndex } from '../../models/dbIndex'
import { DbModel } from '../../models/dbModel'
import { DbTable } from '../../models/dbTable'

export const line: string = '\n'
export const indent: string = '    '

export class DbUtils {
	public static getComment(column: DbColumn): string | undefined {
		let sqlComment = column.comment
		if (!sqlComment && column.label) {
			sqlComment = column.label
		}
		return sqlComment
	}

	/**
	 * Generate names for indexes and foreign keys
	 * @param model the database model
	 * @param maxLength the max length of key name limitation
	 */
	public static genModelNames(model: DbModel, maxLength: number = 64) {
		model.tables.forEach(table => {
			this.genTableNames(table, maxLength)
		})
	}

	/**
	 * Generate names for indexes and foreign keys
	 * - table name + first field
	 * - if there is a duplicate, and more fields
	 * - only keep characters in max length
	 * - if there is a duplicate, remove and last 4 chars and add an index like 0001.
	 * @param table 
	 * @param maxLength 
	 */
	public static genTableNames(table: DbTable, maxLength: number = 64) {
		let nameMap: any = {}
		table.indexes.forEach(index => {
			if (index.name) {
				nameMap[index.name] = index.name
				return
			}
			const columns: string[] = index.columns.split(/,\s*/g)
			index.name = `IK_${table.name}`
			// eslint-disable-next-line no-restricted-syntax
			for (const column of columns) {
				index.name += `_${column}`
				if (!nameMap[index.name]) {
					// if the name is good
					nameMap[index.name] = index.name
					return
				}
			}
		})

		// apply the max length limitation
		nameMap = {}
		let nameIndex = 0
		table.indexes.forEach(index => {
			if (index.name!.length > maxLength) {
				index.name = index.name?.substring(0, maxLength)
			}
			if (!nameMap[index.name!]) {
				// if the name is good
				nameMap[index.name!] = index.name
				return
			}
			nameIndex += 1
			index.name = index.name!.substring(0, maxLength - 4) + nameIndex.toString().padStart(4, '0')
		})

		// foreign keys
		nameMap = {}
		table.foreignKeys.forEach(foreignKey => {
			if (foreignKey.name) {
				nameMap[foreignKey.name] = foreignKey.name
				return
			}
			const columns: string[] = foreignKey.columns.split(/,\s*/g)
			foreignKey.name = `FK_${table.name}`
			// eslint-disable-next-line no-restricted-syntax
			for (const column of columns) {
				foreignKey.name += `_${column}`
				if (!nameMap[foreignKey.name]) {
					// if the name is good
					nameMap[foreignKey.name] = foreignKey.name
					return
				}
			}
		})

		// apply the max length limitation
		nameMap = {}
		nameIndex = 0
		table.foreignKeys.forEach(foreignKey => {
			if (foreignKey.name!.length > maxLength) {
				foreignKey.name = foreignKey.name?.substring(0, maxLength)
			}
			if (!nameMap[foreignKey.name!]) {
				// if the name is good
				nameMap[foreignKey.name!] = foreignKey.name
				return
			}
			nameIndex += 1
			foreignKey.name = foreignKey.name!.substring(0, maxLength - 4) + nameIndex.toString().padStart(4, '0')
		})
	}

	public static renderDefaultName(table: DbTable, column: DbColumn): string {
		return `DF_${DbUtils.renderTableName(table.name)}_${column.name}`
	}

	public static renderFkName(table: DbTable, foreignKey: DbForeignKey): string {
		return DbUtils.renderFkName2(table.name, foreignKey)
	}

	public static renderFkName2(tableName: string, foreignKey: DbForeignKey): string {
		return `FK_${DbUtils.renderTableName(tableName)}_${foreignKey.columns
			.replace(/[()\s]/g, '')
			.replace(/,/g, '_')}`
	}

	public static renderIndexName(table: DbTable, index: DbIndex): string {
		return DbUtils.renderIndexName2(table.name, index)
	}

	public static renderIndexName2(tableName: string, index: DbIndex): string {
		if (index.name) {
			return index.name
		}
		return `IK_${DbUtils.renderTableName(tableName)}_${index.columns
			.replace(/[()\s]/g, '')
			.replace(/,/g, '_')}`
	}

	public static renderPkName(table: DbTable): string {
		return `PK_${DbUtils.renderTableName(table.name)}`
	}

	public static renderTableName(name: string): string {
		return name.replace('\\s', '')
	}

	public static stripBrackets(value: string, stripAll: boolean = false): string {
		let newValue = value
		const minLength = stripAll ? 2 : 4
		while (newValue.length > minLength) {
			if (stripAll) {
				if (newValue.startsWith('(') && newValue.endsWith(')')) {
					newValue = newValue.substring(1, newValue.length - 1)
				} else {
					break
				}
			} else if (newValue.startsWith('((') && newValue.endsWith('))')) {
				newValue = newValue.substring(2, newValue.length - 2)
			} else {
				break
			}
		}

		return newValue
	}

	public static log(data: any): string {
		// eslint-disable-next-line no-console
		console.log(data)
		return ""
	}
}
